package com.example.springspel.interceptor;

import com.example.springspel.annotation.PreAuthorize;
import com.example.springspel.config.SecurityContext;
import com.example.springspel.entity.Permission;
import com.example.springspel.entity.User;
import com.example.springspel.service.PermissionService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class AuthInterceptor implements HandlerInterceptor {

  private final PermissionService permissionService ;
  public AuthInterceptor(PermissionService permissionService) {
    this.permissionService = permissionService ;
  }

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if (handler instanceof HandlerMethod) {
      HandlerMethod handlerMethod = (HandlerMethod) handler;
      PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
      if (preAuthorize != null) {
        User user = SecurityContext.get() ;
        if (user == null) {
          response.getWriter().write("Goto login");
          return false ;
        }
        List<String> allowedPermissions = Arrays.asList(preAuthorize.value()) ;
        List<Permission> permissions = this.permissionService.findPermissions(user.getId()) ;
        if (!hasAllowedPermission(allowedPermissions, permissions)) {
          response.getWriter().write("Access denied");
          return false ;
        }
      }
    }
    return true ;
  }

  private boolean hasAllowedPermission(List<String> allowedPermissions, List<Permission> permissions) {
    List<String> permissionNames = permissions.stream().map(Permission::getName).collect(Collectors.toList());
    return allowedPermissions.stream().anyMatch(permissionNames::contains);
  } 
}